home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1993…ch: Other People's Memory / ADC Developer CD (1993-03) (''Other People's Memory'')_iso / Dev.CD Mar 93.iso / Technical Documentation / Sample Code / DTS_SCSI Code (In Development) / DTS_SCSI_Application.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-01-15  |  16.4 KB  |  555 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        DTS_SCSI_Application.c
  3.     
  4.     
  5.     
  6.     
  7.     Unfortunately, no matter how long awaited, it's still not done.  In fact, this
  8. isn't even a release- this is just an image of the code taken in the middle of
  9. development.
  10.  
  11. THIS CODE DOES NOT WORK AS A WHOLE.  MUCH OF IT IS BUGGY AND / OR INCOMPLETE.
  12. YOU WOULD HAVE TO BE ABSOLUTELY INSANE TO USE ANY OF THIS CODE IN YOUR
  13. PROJECT WITHOUT EXTENSIVE THOUGHT, DEBUGGING AND TESTING.
  14.  
  15.  
  16.  
  17.  
  18.  
  19.  
  20.     Contains:    All application-level code for DTS' SCSI Sample.
  21.  
  22.     Written by:    Colleen Delgadillo, Dennis Hescox, Kent Sandvik, Bryan Stearns
  23.  
  24.     Copyright:    © 1992 by Apple Computer, Inc., all rights reserved.
  25.  
  26.     Change History (most recent first):
  27.  
  28.                    7/22/92    ckd        Changed Kent's cursor handling to SetCursor.
  29.                  7/14/92    khs        Added code for handling the cursor.
  30.                  3/10/92    BJS        Added header; messed with comments.
  31.  
  32.     To Do:
  33.         Add busy cursor rotation.
  34.     
  35.     Notes:
  36.         This application was based on Apple's aptly-named simple sample
  37.         application, Sample. For simplicity, some of the comments in the
  38.         original code dealing with general Macintosh development issues
  39.         have been removed -- instead, we concentrate here on the SCSI 
  40.         issues. See the original Sample source (included with MPW, etc.)
  41.         if you need background on how a Macintosh application is constructed.
  42. */
  43.  
  44. #include <Values.h>
  45. #include <Types.h>
  46. #include <Resources.h>
  47. #include <QuickDraw.h>
  48. #include <Fonts.h>
  49. #include <Events.h>
  50. #include <Windows.h>
  51. #include <Menus.h>
  52. #include <TextEdit.h>
  53. #include <Dialogs.h>
  54. #include <Desk.h>
  55. #include <ToolUtils.h>
  56. #include <Memory.h>
  57. #include <SegLoad.h>
  58. #include <Files.h>
  59. #include <OSUtils.h>
  60. #include <OSEvents.h>
  61. #include <DiskInit.h>
  62. #include <Packages.h>
  63. #include <Traps.h>
  64. #ifdef INCLUDEVMCALLS
  65. #include <GestaltEqu.h>
  66. extern void NextFunction();     // a dummy function -- tells us where this one ends.
  67. #endif
  68.  
  69. #define __FILE_NUMBER__        0x4000    // Used by assert() when there's no debugger installed
  70.                                     //  to let us know where we're failing
  71.  
  72. #include "DTS_SCSI_Application.h"
  73. #include "DTS_SCSI_Format.h"
  74. #include "DTS_SCSI_Debug.h"
  75.  
  76.  
  77. /********************************************************************************************
  78.  *
  79.  * Global Variable Definitions
  80.  * (The "g" prefix is used to emphasize that a variable is global.)
  81.  *
  82.  ********************************************************************************************/
  83.  
  84. // This machine's feature set, set up by Initialize
  85. SysEnvRec gSysEnvironment; 
  86.  
  87. // Our main dialog window's storage
  88. DialogRecord gMainDialog; 
  89.  
  90. // Our error-mapping string resource
  91. ErrorMappingHandle gErrorMappings; 
  92.  
  93.  
  94.  
  95. /********************************************************************************************
  96.  *
  97.  * Handy preprocessor macros. 
  98.  * 
  99.  * These exist for efficiency and readability, at a cost of clarity: macros can 
  100.  * obsure the actual workings of a C program. By clearly documenting these macros, 
  101.  * and gathering them together where they can be studied together, we hope to minimize 
  102.  * these problems.
  103.  *
  104.  ********************************************************************************************/
  105.  
  106. // These macros extract the high-order and low-order words of a long integer.
  107. // They're (much) more efficient than the Toolbox traps.
  108. #define HiWrd(aLong)    (((aLong) >> 16) & 0xFFFF)
  109. #define LoWrd(aLong)    ((aLong) & 0xFFFF)
  110.  
  111. // These macros allow us to access fields of a rectangle as points.
  112. #define TopLeft(aRect)    (* (Point *) &(aRect).top)
  113. #define BotRight(aRect)    (* (Point *) &(aRect).bottom)
  114.  
  115.  
  116. /********************************************************************************************
  117.  *
  118.  * Dialog & Alert Utilities
  119.  *
  120.  ********************************************************************************************/
  121. // *** Kill all pragma statements and document why they have been removed. ??? WHAT/WHY?
  122. //
  123. // Enable or disable this dialog control
  124. //
  125. void SetDialogItemEnabling(DialogPtr dialog, short item, Boolean enabled) {
  126.     Rect itemBox;
  127.     short itemType;
  128.     ControlHandle itemHandle;
  129.     
  130.     GetDItem(dialog, item, &itemType, (Handle *) &itemHandle, &itemBox);
  131.     HiliteControl(itemHandle, enabled ? 0 : 255);
  132. }
  133.  
  134. //
  135. // Utility routine: Set the text of a dialog item to this Pascal string. 
  136. // (The string must be locked in memory; it may be released after 
  137. // calling this routine.)
  138. //
  139. #pragma segment Main
  140. void SetDialogItemText(DialogPtr dialog, short item, Str255 text) {
  141.     Rect itemBox;
  142.     short itemType;
  143.     Handle itemHandle;
  144.     
  145.     GetDItem(dialog, item, &itemType, &itemHandle, &itemBox);
  146.     SetIText(itemHandle, text);
  147. } // SetDialogItemText
  148.  
  149. //
  150. // Four wrappers for SetDialogItemText: one pair sets the drive info string,
  151. // the other sets the message string. Within each pair, one accepts the
  152. // actual text as a parameter; the other gets it from our string list.
  153. //
  154. #pragma segment Main
  155. void PostMessage(Str255 aString) {
  156.     SetDialogItemText((DialogPtr) &gMainDialog, kMessageText, aString);
  157. }
  158. #pragma segment Main
  159. void SetDriveInfoText(Str255 aString) {
  160.     SetDialogItemText((DialogPtr) &gMainDialog, kDriveInfoText, aString);
  161. }
  162. #pragma segment Main
  163. void PostMessageFromList(short index) {
  164.     Str255 tempString;
  165.     GetIndString(tempString, kStringList, index);
  166.     SetDialogItemText((DialogPtr) &gMainDialog, kMessageText, tempString);
  167. }
  168. #pragma segment Main
  169. void SetDriveInfoTextFromList(short index) {
  170.     Str255 tempString;
  171.     GetIndString(tempString, kStringList, index);
  172.     SetDialogItemText((DialogPtr) &gMainDialog, kDriveInfoText, tempString);
  173. }
  174.  
  175. //
  176. // Look up an error string and put its corresponding message in
  177. // the message string of our main dialog.
  178. //
  179. void PostError(short errornumber) {
  180.     short i, errorCount;
  181.     ErrorMapping *thisError;
  182.     
  183.     // Find our error-mapping table resource; figure out how big it is.
  184.     errorCount = SizeResource((Handle) gErrorMappings) / sizeof(ErrorMapping);
  185.             
  186.     // Walk through the table, looking for our error
  187.     for (i = 0, thisError = *gErrorMappings; i < errorCount; i++, thisError++) {
  188.         if (thisError->errNum == errornumber) { // found it!
  189.             HLock((Handle) gErrorMappings);
  190.             PostMessage(thisError->message);
  191.             HUnlock((Handle) gErrorMappings);
  192.             return;
  193.         }
  194.     }
  195.     // We didn't find the message we needed! Substitute a generic one.
  196.     // *** it'd be nice to include the number here.
  197.     PostMessageFromList(kUnknownLowLevelError);
  198. } // PostError      
  199.  
  200.  
  201. //
  202. // Draw procedure for the userItems in our main dialog.
  203. // It simply frames the item's box; if the item happens to be one-dimensional,
  204. // it appears as a line.
  205. //
  206. pascal void FrameUserItems(DialogPtr dialog, short item) {
  207.     Rect itemBox;
  208.     short dummyType;
  209.     Handle dummyHandle;
  210.     
  211.     // Get the box, set the pen, frame the box; the port's already set.
  212.     GetDItem(dialog, item, &dummyType, &dummyHandle, &itemBox);
  213.     PenSize(1,1);
  214.     FrameRect(&itemBox);
  215. }
  216.  
  217. /********************************************************************************************
  218.  *
  219.  * Events and Commands
  220.  *
  221.  ********************************************************************************************/
  222.  
  223. //
  224. // Put up our About box.
  225. //
  226. // We don't bother checking for memory errors here because
  227. // in this simple application, we don't have documents; we 
  228. // can only be called from the main event loop, when we've
  229. // got beaucoup free RAM.
  230. //
  231. void DoAbout() {
  232.     DialogPtr    dialog;
  233.     short        item = 0;
  234.  
  235.     // Get the dialog
  236.     dialog = GetNewDialog(kAboutBox, NULL, (WindowPtr) -1L);
  237.  
  238.     assert(dialog != 0,"\Couldn't get the about box window");
  239.     
  240.     if (dialog != NULL) {
  241.         // Let the user run it until he or she clicks OK
  242.         ShowWindow(dialog);
  243.         SetPort(dialog);
  244.         while (item != 1)
  245.             ModalDialog(NULL,&item);
  246.         
  247.         DisposDialog(dialog);
  248.     } else {
  249.         // *** Should we SysBeep when we fail?  It should never happen.
  250.     }
  251. } // DoAbout
  252.  
  253. //
  254. // Switch to the next eligible drive, if we can find one.
  255. // If we can, put its ID in the SCSI device text item (*** eventually,
  256. // try to get its volume name (if any)). If we can't find an eligible drive,
  257. // put an appropriate error message in the message text. Either way, set the
  258. // enabling of the buttons in our window appropriately.
  259. //
  260. void DoDrive() {
  261.     Str255 number;
  262.     SCSIAddress newDevice;
  263.     Boolean success;
  264.     short anErr;
  265.     
  266.     // Try to find the next drive. This will return 0 if we found a different
  267.     // drive than the current one, kNoMoreDevices
  268.     anErr = NextEligibleDevice(); // try to find the next drive.
  269.     switch (anErr) {
  270.         case noErr: // We found a new drive.
  271.             // Get its SCSI ID and put it in the SCSI Message box
  272.             newDevice = CurrentDevice();
  273.             NumToString(newDevice, number);
  274.             SetDialogItemText((DialogPtr) &gMainDialog, kDriveInfoText, number);
  275.         
  276.             // *** eventually, get the volume name from the drive. For now,
  277.             // just clear the message area
  278.             SetDialogItemText((DialogPtr) &gMainDialog, kMessageText, "");
  279.             break;
  280.         
  281.         case kNoOtherValidDrives: // We couldn't find a drive other than the current one.
  282.             // We don't need to change the enabling of our buttons, or the
  283.             // displayed current drive ID, but we should put up a message saying
  284.             // that this is the only good one we found.
  285.             PostMessageFromList(kOnlyOneOfOurDevice);
  286.             anErr = noErr; // don't disable the buttons.
  287.             break;
  288.         
  289.         default:
  290.             // We didn't find a usable drive.
  291.             SetDialogItemText((DialogPtr) &gMainDialog, kDriveInfoText, "");
  292.             PostMessageFromList(kNoSCSIDevices);
  293.             break;
  294.     }
  295.     
  296.     // Enable or disable the appropriate buttons based on whether we have
  297.     // a valid drive.
  298.     success = (anErr == noErr);
  299.     SetDialogItemEnabling((DialogPtr) &gMainDialog, kTestButton, success);
  300.     SetDialogItemEnabling((DialogPtr) &gMainDialog, kUpdateButton, success);
  301.     SetDialogItemEnabling((DialogPtr) &gMainDialog, kFormatButton, success);
  302. }
  303.  
  304. //
  305. // Ask the user if he/she's sure that this drive should be trashed.
  306. // Then trash it.
  307. //
  308. void DoFormat() {
  309.     short        anErr;
  310.     
  311.     // *** Document why we have this!
  312. #ifdef DEBUG    // *** See if the user's holding down the option key
  313.     EventRecord dummy;
  314.     OSEventAvail(0,&dummy);
  315. #endif
  316.  
  317. #ifndef DEBUG    // For reducing debugging tedium - don't confirm format.
  318.     if (StopAlert(kConfirmFormatAlert, NULL) == ok)
  319. #endif
  320.     {
  321.         // Attempt to unmount the volume & unload its driver
  322.         
  323.         anErr = UnmountCurrentDevice();
  324.         assert(anErr == noErr,"Couldn't unmount!");
  325.  
  326.         if (anErr) {
  327.             PostMessageFromList(kFormatError);
  328.             // *** StopAlert(kCouldntUnmount, NULL);  Why commented out? *** Dialog never got designed
  329.             return;
  330.         }
  331.         
  332.         // Tell the user we be formattin'
  333.         PostMessageFromList(kFormatting);
  334.         DrawDialog((DialogPtr) &gMainDialog); // force an update
  335.  
  336.         // Format the media.
  337.         
  338. #ifdef DEBUG    // For debugging, we only format if the option key is down.
  339.         anErr = noErr;
  340.         if (dummy.modifiers & optionKey)
  341. #endif
  342.             anErr = FormatCurrentDevice();
  343.  
  344.         // Write a generic partition map and the driver, install the driver,
  345.         //  mount the new volume and DIZero it.
  346.         if (anErr == noErr)
  347.             anErr = PartitionCurrentDevice();
  348.         
  349.         // Update the message
  350.         PostMessageFromList(anErr == noErr ? kFormattingCompleted : kFormatError);
  351.     }
  352. }
  353.  
  354. //
  355. // Update the driver on a drive
  356. //
  357. void DoUpdate() {
  358.     short        err;
  359.     
  360.     // If I was going to confirm that a user wanted to update the driver, I would
  361.     // put the dialog here, but I think having the newest driver is always the
  362.     // best thing, and because there's little risk of data loss, doesn't need to
  363.     // be confirmed.  Ideally, the updater would read the version of the driver
  364.     // on the disk and compare it to this version, asking for confirmation if
  365.     // the version being replaced was newer then the one being installed.
  366.     
  367.     // First, we'll unmount and unload the current driver
  368.     err = UnmountCurrentDevice();
  369.     assert(!err,"Couldn't unmount for updating");
  370.     
  371.     if (err)
  372.     {    // *** Put the alert here (maybe one consistant error alert?)
  373.         PostMessageFromList(kUpdateError);
  374.         return;
  375.     }
  376.     
  377.     // Tell the user we're updating the driver and get it drawn
  378.     PostMessageFromList(kUpdating);
  379.     DrawDialog((DialogPtr) &gMainDialog);
  380.     
  381.     // Go off and actually do the update.
  382.     err = UpdateCurrentDevice();
  383.     
  384.     if (err == noErr)
  385.         PostMessageFromList(kUpdateCompleted);
  386.     else
  387.         PostMessageFromList(kUpdateError);
  388. }
  389.  
  390. //
  391. // Our main event loop
  392. //
  393. #pragma segment Main
  394. void MainEventLoop() {
  395.     Boolean done = false;
  396.     short item;
  397.     
  398.     SetPort((DialogPtr) &gMainDialog); // Make sure we're in the right port
  399.     do {
  400.         ModalDialog(NULL, &item);
  401.                 
  402.         switch (item) {
  403.             case kAboutButton:
  404.                 DoAbout();
  405.                 break;
  406.                 
  407.             case kFormatButton:
  408.                 SetCursor(*GetCursor(watchCursor));
  409.                 DoFormat();
  410.                 SetCursor(&qd.arrow);
  411.                 break;
  412.                 
  413.             case kUpdateButton:
  414.                 DoUpdate();
  415.                 break;
  416.                 
  417.             case kDriveButton:
  418.                 DoDrive();
  419.                 break;
  420.             
  421.             case kQuitButton:
  422.                 done = true;
  423.                 break;
  424.         }
  425.     } while (!done);
  426. } // MainEventLoop    
  427.  
  428.  
  429. /********************************************************************************************
  430.  *
  431.  * Initialization
  432.  *
  433.  ********************************************************************************************/
  434.  
  435.  
  436. // 
  437. // Is this trap implemented?
  438. // (Note that this depends on gSysEnvironment)
  439. //
  440. #pragma segment Initialize
  441. Boolean TrapAvailable(short trapNumber, TrapType trapType) {
  442.     // if we're running on a 512KE, Plus, or SE, the tool traps only go to 0x1FF
  443.     if ((trapType == ToolTrap) && 
  444.                   (gSysEnvironment.machineType > envMachUnknown) &&
  445.                 (gSysEnvironment.machineType < envMacII)) { 
  446.           // This is a 512KE, Plus, or SE; if the trap is > 0x1ff, it must be unimplemented.
  447.         trapNumber = trapNumber & 0x03FF;
  448.         if (trapNumber > 0x01FF) trapNumber = _Unimplemented;
  449.     }
  450.     
  451.     return NGetTrapAddress(trapNumber, trapType) != GetTrapAddress(_Unimplemented);
  452. } // TrapAvailable
  453.  
  454.  
  455. //
  456. // Report a fatal initialization error to the user, then ExitToShell.
  457. //
  458. #pragma segment Initialize
  459. void FatalInitializationError() {
  460.     SetCursor(&qd.arrow);
  461.     Alert(kInsufficientSystem, nil);
  462.     ExitToShell();
  463. } // FatalInitializationError
  464.  
  465.  
  466. // Initialize: Set up the whole world, including global variables, Toolbox managers,
  467. // and menus. We also create our one application window at this time.
  468. //
  469. #pragma segment Initialize
  470. void Initialize() {
  471.     Rect     itemBox;
  472.     short    itemType;
  473.     Handle    itemHandle;
  474.     short    item;
  475.     long    total, contig;
  476.     Str255    vendorString, productString, revisionString;
  477.     
  478.     // Initialize the Toolbox
  479.     InitGraf((Ptr) &qd.thePort);
  480.     InitFonts();
  481.     InitWindows();
  482.     InitMenus();
  483.     TEInit();
  484.     InitDialogs(NULL);
  485.     InitCursor();
  486.         
  487.     // Inquire as to our environment. If we don't have 128K ROMs or better,
  488.     // we don't have SCSI. Quit.
  489.     SysEnvirons(curSysEnvVers, &gSysEnvironment);    
  490.     if (gSysEnvironment.machineType < 0) 
  491.         FatalInitializationError(); // exit
  492.     
  493.     // Do we have enough memory to run?
  494.     PurgeSpace(&total, &contig);
  495.     if (total < kMinimumSpace)
  496.         FatalInitializationError();
  497.     
  498.     // Load our error-mapping table resource and string list. We
  499.     // keep these in memory to simplify our memory management.
  500.     gErrorMappings = (ErrorMappingHandle) GetResource(kErrorMappingResourceType, kErrorMappingResourceID);
  501.     if ((!gErrorMappings) || (!GetResource('STR#', kStringList)))
  502.         FatalInitializationError();
  503.     
  504.     // Tell the low-level code what vendor string we're looking for
  505.     GetIndString(vendorString, kStringList, kVendorString);
  506.     GetIndString(productString, kStringList, kProductString);
  507.     GetIndString(revisionString, kStringList, kRevisionString);
  508.     SetValidationInfo(vendorString, productString, revisionString);
  509.         
  510.     // Get our window - if we can't, die. 
  511.     if (!GetNewDialog(kMainDialog, &gMainDialog, (WindowPtr) -1L /*in front*/)) 
  512.         FatalInitializationError();
  513.     
  514.     // Install our userItem's draw procedure
  515.     for (item = kFirstUserItem; item <= kLastUserItem; ++item) {
  516.         GetDItem((DialogPtr) &gMainDialog, item, &itemType, &itemHandle, &itemBox);
  517.         SetDItem((DialogPtr) &gMainDialog, item, itemType, (Handle) FrameUserItems, &itemBox);
  518.     }
  519.     
  520.     // Show the window, and draw it, so that the user has something to look at
  521.     // while we're trolling for qualified devices.
  522.     ShowWindow((DialogPtr) &gMainDialog);
  523.     DrawDialog((DialogPtr) &gMainDialog);
  524.     
  525.     // Find a usable SCSI device and make it the default one.
  526.     DoDrive();
  527. }
  528.  
  529.  
  530. //
  531. // The main entry point:
  532. //     - Get rid of the data-initialization segment, to avoid fragmenting memory
  533. //  - Expand the application heap to its maximum
  534. //  - Finish our initialization
  535. //  - Unload the segment containing our initialization
  536. //  - Run!
  537. //
  538. #pragma segment Main
  539. main() {    
  540.     extern void _DataInit();
  541.     UnloadSeg((Ptr) _DataInit);    // Unload the data-initialization segment,
  542.                                 // to avoid fragmenting memory.
  543.  
  544.     MaxApplZone(); // expand the heap so code segments load at the top
  545.     Initialize(); // initialize the program
  546.     UnloadSeg((Ptr) Initialize); // unload the initialization segment
  547.     
  548.     MainEventLoop(); // Run!
  549.  
  550.     // We're going to quit. We could close our main dialog window, but 
  551.     // since our heap will be destroyed shortly, why bother?
  552.     // *** OK, we probably should close the dialog window.
  553.     ExitToShell();
  554. }
  555.